//! simink 内核启动早期内存分配器
//!
//! 在 buddy 和 slub 分配器初始化之前, memblock 用于预留物理内存, 收集可用物理内存以及提供早期内存分配能力
//!
//! * add 模块提供了内存地址的添加, 预留, 移除, 其他模块基于此执行各种操作
//! * alloc 模块通过 add 模块添加的内存进行分配, 释放
//! * iter 模块提供了各种迭代 Memblock 的方法
//! * mark 模块提供了一系列标识功能, 记录和划分不同 MemblockRegion
//! * mb 提供了模块的统计信息以及设置一些特殊属性
//!
//! 检查 Memblock 的统计信息, 可以使用 `{}` 和 `{:?}`, Memblock 实现了 Debug 和 Display Trait

// 内部引用的 mod
mod common;
mod display;

// 重新导出的 mod
pub mod add;
pub mod alloc;
pub mod iter;
pub mod mark;
pub mod mb;

use bitflags::bitflags;

use crate::vm::addr::paddr::Paddr;

use self::common::{memblock_isolate_range, memblock_remove_range, memblock_remove_region};

// 记录每个 MemblockType 有多少个 MemblockRegion
const MEMBLOCK_REGIONS_NUM: usize = 64;
// 表示可以任意地址分配地址
const MEMBLOCK_ALLOC_ANYWHERE: usize = usize::MAX;
// 表示地址的分配受 current_limit 限制
const MEMBLOCK_ALLOC_ACCESSIBLE: usize = 0;

bitflags! {
    /// 标记 MemblockRegion, 用于区分不同内存区域
    ///
    /// * MEMBLOCK_NONE 是所有 MemblockRegion 的默认值
    /// * MEMBLOCK_DMA 标记 MemblockRegion 为 DMA, 在一些系统中可以将特定区域标记为 DMA, 这样在分配 DMA 专用内存时可以确保地址的合法性
    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    pub struct MemblockFlags: u32 {
        const MEMBLOCK_NONE  = 0;
        const MEMBLOCK_DMA   = 1;
    }
}

/// 描述一段内存域, 包括起始地址, 大小以及域的 flags
#[derive(Copy, Clone, Debug)]
pub struct MemblockRegion {
    base: Paddr,
    size: usize,
    flags: MemblockFlags,
}

/// 描述 MemblockRegion 的一组集合
///
/// MemblockType 包含了该集合能存储的最大 MemblockRegion 的数量以及当前已存储的数量
///
/// 同时记录了该 MemblockType 中所存储的 MemblockRegion 的总内存大小
#[derive(Debug)]
pub struct MemblockType {
    cnt: usize,
    max: usize,
    total_size: usize,
    regions: [MemblockRegion; MEMBLOCK_REGIONS_NUM],
    name: &'static str,
}

/// Memblock 分配器的元数据
///
/// 分配器的元数据记录了以下信息:
/// * 记录分配器当前能分配的最大地址
/// * 记录向下分配时的最小地址, 这个地址默认是 0, 当在内核中进行自顶向下分配时, 我们需要避开 _end 段, 可以手动设置这个值来避开 _end 段
/// * 使用一个 MemblockType (memory) 来记录所有可用内存
/// * 使用一个 MemblockType (reserved) 来记录所有预留内存 (当在 alloc 模块中进行物理内存分配时, 我们从 memory 中寻找一块内存, 并且该内存需要避开 reserved 中记录的内存)
/// * 记录我们自顶向下分配还是自底向上分配
#[derive(Debug)]
pub struct Memblock {
    current_limit: Paddr,
    bottom_limit: Paddr,
    memory: MemblockType,
    reserved: MemblockType,
    bottom_up: bool,
}

impl Default for Memblock {
    fn default() -> Self {
        Self::new()
    }
}

impl Memblock {
    pub fn new() -> Self {
        Self {
            current_limit: Paddr::from(MEMBLOCK_ALLOC_ANYWHERE),
            bottom_limit: Paddr::from(0),
            memory: MemblockType {
                cnt: 1,
                max: MEMBLOCK_REGIONS_NUM,
                total_size: 0,
                regions: [MemblockRegion {
                    base: Paddr::from(0),
                    size: 0,
                    flags: MemblockFlags::MEMBLOCK_NONE,
                }; MEMBLOCK_REGIONS_NUM],
                name: "memory",
            },
            reserved: MemblockType {
                cnt: 1,
                max: MEMBLOCK_REGIONS_NUM,
                total_size: 0,
                regions: [MemblockRegion {
                    base: Paddr::from(0),
                    size: 0,
                    flags: MemblockFlags::MEMBLOCK_NONE,
                }; MEMBLOCK_REGIONS_NUM],
                name: "reserved",
            },
            bottom_up: false,
        }
    }

    fn __find_max_addr(&self, mut limit: usize) -> usize {
        let mut max_addr = usize::MAX;

        for rgn in self.iter_each_mem() {
            if limit <= rgn.1 {
                max_addr = rgn.0.to_value() + limit;
                break;
            }
            limit -= rgn.1;
        }
        max_addr
    }

    /// 强制限制内存总量
    ///
    /// 根据传入的 limit (指明内存的最大限制) 参数, 限制当前 Memblock 的最大内存总量
    ///
    /// 注意:
    /// * 如果限制成功, 那么会强制移除多余的 MemblockRegion
    /// * 如果由于某些原因不能成功移除 MemblockRegion 该函数将会 panic
    pub fn memblock_enforce_memory_limit(&mut self, limit: usize) {
        if limit == 0 {
            return;
        }

        let max_addr = self.__find_max_addr(limit);
        if max_addr == usize::MAX {
            return;
        }

        if memblock_remove_range(&mut self.memory, Paddr::from(max_addr), usize::MAX) == Ok(())
            && memblock_remove_range(&mut self.reserved, Paddr::from(max_addr), usize::MAX)
                == Ok(())
        {
            return;
        }
        panic!("memblock_enforce_memory_limit failed!");
    }

    /// 调整内存使用范围
    ///
    /// 根据传入的 base 和 size 参数, 调整内存的使用范围
    ///
    /// 注意:
    /// * 如果调整成功, 那么会移除多余的 MemBlockRegion
    /// * 如果由于某些原因不能成功移除 MemBlockRegion 该函数将会 panic
    pub fn cap_memory_range(&mut self, base: Paddr, size: usize) {
        if size == 0 {
            return;
        }
        let mut start_idx = 0;
        let mut end_idx = 0;
        if memblock_isolate_range(&mut self.memory, base, size, &mut start_idx, &mut end_idx)
            == Err(())
        {
            return;
        }
        for i in (end_idx as usize..self.memory.cnt).rev() {
            memblock_remove_region(&mut self.memory, i);
        }
        for i in (0..start_idx).rev() {
            memblock_remove_region(&mut self.memory, i as usize);
        }
        if memblock_remove_range(&mut self.reserved, Paddr::from(0), size) == Ok(())
            && memblock_remove_range(&mut self.reserved, base + size, usize::MAX) == Ok(())
        {
            return;
        }

        panic!("memblock_cap_memory_range failed!");
    }

    /// 限制内存总量并调整内存范围为 [0 - max_addr]
    ///
    /// 根据传入的 limit 限制内存总量, 并根据限制后的 max_addr 调整内存的使用范围为 [0 - max_addr]
    ///
    /// 注意:
    /// * 如果限制调整成功, 那么会移除多余的 MemBlockRegion
    /// * 如果由于某些原因不能成功移除 MemBlockRegion 该函数将会 panic
    pub fn mem_limit_remove_map(&mut self, limit: usize) {
        if limit == 0 {
            return;
        }
        let max_addr = self.__find_max_addr(limit);
        if max_addr == usize::MAX {
            return;
        }
        self.cap_memory_range(Paddr::from(0), max_addr);
    }
}
